package me.macd.mindoc.dao.impl;

import me.macd.mindoc.util.NameHandler;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.lang.Nullable;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: mindoc
 * @description: ${description}
 * @author: 2018-11-01
 * @create: 2018-11-01 20:59
 */
public class CommonRowMapper<T> implements RowMapper<T> {
    private Class<T> clazz;
    private Map<String, Field> fieldMap;

    public CommonRowMapper(Class<T> clazz, NameHandler nameHandler) {
        this.clazz = clazz;
        fieldMap = new HashMap<>();
        for (Field field : clazz.getDeclaredFields()) {
            fieldMap.put(nameHandler.columnName(field.getName()), field);
        }
    }

    @Nullable
    @Override
    public T mapRow(ResultSet rs, int rowNum) throws SQLException {
        T obj;
        try {
            obj = clazz.newInstance();
            final ResultSetMetaData metaData = rs.getMetaData();
            int columnLength = metaData.getColumnCount();
            String columnName;

            for (int i = 1; i <= columnLength; i++) {
                columnName = metaData.getColumnName(i);
                // 统一小写
                Field field = fieldMap.get(columnName.toLowerCase());
                if (field == null) {
                    continue;
                }
                Class fieldClazz = field.getType();

                field.setAccessible(true);

                // fieldClazz == Character.class || fieldClazz == char.class
                if (fieldClazz == int.class || fieldClazz == Integer.class) { // int
                    field.set(obj, rs.getInt(columnName));
                } else if (fieldClazz == boolean.class || fieldClazz == Boolean.class) { // boolean
                    field.set(obj, rs.getBoolean(columnName));
                } else if (fieldClazz == String.class) { // string
                    field.set(obj, rs.getString(columnName));
                } else if (fieldClazz == float.class) { // float
                    field.set(obj, rs.getFloat(columnName));
                } else if (fieldClazz == double.class || fieldClazz == Double.class) { // double
                    field.set(obj, rs.getDouble(columnName));
                } else if (fieldClazz == BigDecimal.class) { // bigdecimal
                    field.set(obj, rs.getBigDecimal(columnName));
                } else if (fieldClazz == short.class || fieldClazz == Short.class) { // short
                    field.set(obj, rs.getShort(columnName));
                } else if (fieldClazz == Date.class) { // date
                    field.set(obj, rs.getTimestamp(columnName));
                } else if (fieldClazz == Timestamp.class) { // timestamp
                    field.set(obj, rs.getTimestamp(columnName));
                } else if (fieldClazz == Long.class || fieldClazz == long.class) { // long
                    field.set(obj, rs.getLong(columnName));
                }

                field.setAccessible(false);
            }
        } catch (InstantiationException | IllegalAccessException e) {
            throw new SQLException(e);
        }
        return obj;
    }
}
